home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 11 / CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso / cucd / graphics / mpimage / si / parse.c < prev    next >
C/C++ Source or Header  |  1996-12-01  |  11KB  |  451 lines

  1. /*  
  2.  * parse.c - iffparse file IO support module
  3.  *   based on some of looki.c by Leo Schwab
  4.  *
  5.  * The filename for clipboard is -c or -cUnit as in -c0 -c1 etc. (default 0)
  6.  *
  7.  * 39.10 - fix CloseClipboard() cast to (struct ClipboardHandle *)
  8.  */
  9.  
  10. #include <exec/types.h>
  11.  
  12. #include "iffp/iff.h"
  13.  
  14. #define CATCOMP_NUMBERS
  15. #include "messages.h"
  16.  
  17. /* local function prototypes */
  18.  
  19. static LONG __asm stdio_stream(register __a0 struct Hook *, register __a2 struct IFFHandle *, register __a1 struct IFFStreamCmd *);
  20.  
  21. UBYTE *omodes[2] = {"r","w"};
  22.  
  23.  
  24. /* openifile
  25.  *
  26.  * Passed a ParseInfo structure with a not-in-use IFFHandle, filename
  27.  *   ("-c" or -cUnit like "-c1" for clipboard), and IFF open mode
  28.  *   (IFFF_READ or IFFF_WRITE) opens file or clipboard for use with
  29.  *   iffparse.library support modules.
  30.  *
  31.  * Returns 0 for success or an IFFERR (libraries/iffparse.h)
  32.  */
  33.  
  34. LONG openifile(struct ParseInfo *pi, UBYTE *filename, ULONG iffopenmode)
  35. {
  36.     struct IFFHandle    *iff;
  37.     BOOL    cboard;
  38.     ULONG     unit = PRIMARY_CLIP;
  39.     LONG     error;
  40.  
  41.     if(!pi)            return(CLIENT_ERROR);
  42.         if(!(iff=pi->iff))    return(CLIENT_ERROR);
  43.  
  44.     cboard = (*filename == '-'  &&  filename[1] == 'c');
  45.      if(cboard && filename[2])    unit = atoi(&filename[2]);
  46.  
  47.     if (cboard)
  48.         {
  49.         /*
  50.          * Set up IFFHandle for Clipboard I/O.
  51.          */
  52.         pi->clipboard = TRUE;
  53.         if (!(iff->iff_Stream =
  54.                 (ULONG)OpenClipboard(unit)))
  55.             {
  56.             message1(SI(MSG_IFFP_NOCLIP_D),unit);
  57.             return(NOFILE);
  58.             }
  59.         InitIFFasClip(iff);
  60.         }
  61.     else
  62.         {
  63.         pi->clipboard = FALSE;
  64.         /*
  65.          * Set up IFFHandle for buffered stdio I/O.
  66.          */
  67.         if (!(iff->iff_Stream = (ULONG)
  68.            fopen(filename, omodes[iffopenmode & 1])))
  69.             {
  70.             message1(SI(MSG_IFFP_NOFILE_S),filename);
  71.             return(NOFILE);
  72.             }
  73.         else initiffasstdio(iff);
  74.         }
  75.  
  76.     D(bug("%s file opened: \n", cboard ? "[Clipboard]" : (char *)filename));
  77.  
  78.     pi->filename = filename;
  79.  
  80.     error=OpenIFF(iff, iffopenmode);
  81.  
  82.     pi->opened = error ? FALSE : TRUE;    /* currently open handle */
  83.  
  84.     D(bug("OpenIFF error = %ld\n",error));
  85.     return(error);
  86. }
  87.  
  88.  
  89. /* closeifile
  90.  *
  91.  * closes file or clipboard opened with openifile, and frees all
  92.  *   iffparse context parsed by parseifile.
  93.  *
  94.  * Note - You should closeifile as soon as possible if using clipboard
  95.  *   ("-c[n]").  You also need to closeifile if, for example, you wish to
  96.  *   reopen the file to write changes back out.  See the copychunks.c
  97.  *   module for routines which allow you clone the chunks iffparse has
  98.  *   gathered so that you can closeifile and still be able to modify and
  99.  *   write back out gathered chunks.
  100.  *   
  101.  */
  102.  
  103. void closeifile(struct ParseInfo *pi)
  104. {
  105. struct IFFHandle *iff;
  106.  
  107.     D(bug("closeifile:\n"));
  108.  
  109.     if(!pi)            return;
  110.         if(!(iff=pi->iff))    return;
  111.  
  112.     DD(bug("closeifile: About to CloseIFF if open, iff=$%lx, opened=%ld\n",
  113.             iff, pi->opened));
  114.  
  115.     if(pi->opened)    CloseIFF(iff);
  116.  
  117.     DD(bug("closeifile: About to close %s, stream=$%lx\n",
  118.             pi->clipboard ? "clipboard" : "file", iff->iff_Stream));
  119.     if(iff->iff_Stream)
  120.         {
  121.         if (pi->clipboard)
  122.            CloseClipboard((struct ClipboardHandle *)(iff->iff_Stream));
  123.         else
  124.            fclose ((FILE *)(iff->iff_Stream));
  125.         }
  126.  
  127.     iff->iff_Stream = NULL;
  128.     pi->clipboard = NULL;
  129.     pi->opened = NULL;
  130. }
  131.  
  132.  
  133. /* parseifile
  134.  *
  135.  * Passed a ParseInfo with an initialized and open IFFHandle,
  136.  *  grouptype (like ID_FORM), groupid (like ID_ILBM),
  137.  *  and TAG_DONE terminated longword arrays of type,id
  138.  *  for chunks to be grabbed, gathered, and stopped on
  139.  *  (like { ID_ILBM, ID_BMHD, ID_ILBM, ID_CAMG, TAG_DONE })
  140.  *  will parse an IFF file, grabbing/gathering and stopping
  141.  *  on specified chunk.
  142.  *
  143.  * Note - you can call getcontext() (to continue after a stop chunk) or
  144.  *  nextcontext() (after IFFERR_EOC, to parse next form in the same file)
  145.  *  if you wish to continue parsing the same IFF file.  If parseifile()
  146.  *  has to delve into a complex format to find your desired FORM, the
  147.  *  pi->hunt flag will be set.  This should be a signal to you that
  148.  *  you may not have the capability to simply modify and rewrite
  149.  *  the data you have gathered.
  150.  *
  151.  * Returns 0 for success else and IFFERR (libraries/iffparse.h)
  152.  */ 
  153.  
  154. LONG parseifile(pi,groupid,grouptype,propchks,collectchks,stopchks)
  155. struct    ParseInfo *pi;
  156. LONG groupid, grouptype;
  157. LONG *propchks, *collectchks, *stopchks;
  158. {
  159. struct IFFHandle *iff;    
  160. register struct ContextNode    *cn;
  161. LONG            error = 0L;
  162.  
  163.  
  164.     D(bug("parseifile:\n")); 
  165.  
  166.         if(!(iff=pi->iff))    return(CLIENT_ERROR);
  167.  
  168.     if(!iff->iff_Stream)    return(IFFERR_READ);
  169.  
  170.     pi->hunt = FALSE;
  171.  
  172.     /*
  173.      * Declare property, collection and stop chunks.
  174.      */
  175.     if (propchks)
  176.       if (error = PropChunks (iff, propchks, chkcnt(propchks)))
  177.         return (error);
  178.     if (collectchks)
  179.       if (error =
  180.           CollectionChunks(iff, collectchks, chkcnt(collectchks)))
  181.         return (error);
  182.     if (stopchks)
  183.       if (error = StopChunks (iff, stopchks, chkcnt(stopchks)))
  184.         return (error);
  185.  
  186.     /*
  187.      * We want to stop at the end of an ILBM context.
  188.      */
  189.     if (grouptype)
  190.       if (error = StopOnExit (iff, grouptype, groupid))
  191.         return(error);
  192.  
  193.     /*
  194.      * Take first parse step to enter main chunk.
  195.      */
  196.     if (error = ParseIFF (iff, IFFPARSE_STEP))
  197.         return(error);
  198.  
  199.     /*
  200.      * Test the chunk info to see if simple form of type we want (ILBM).
  201.      */
  202.     if (!(cn = CurrentChunk (iff)))
  203.         {
  204.         /*
  205.          * This really should never happen.  If it does, it means
  206.          * our parser is broken.
  207.          */
  208.         message(SI(MSG_IFFP_NOTOP));
  209.         return(NOFILE);
  210.         }
  211.  
  212.     if (cn->cn_ID != groupid  ||  cn->cn_Type != grouptype)
  213.         {
  214.         
  215.         D(bug("This is a(n) %.4s.%.4s.  Looking for embedded %.4s's...\n",
  216.           &cn->cn_Type, &cn->cn_ID, &grouptype));
  217.  
  218.         pi->hunt = TRUE;    /* Warning - this is a complex file */
  219.         }
  220.  
  221.     if(!error)    error = getcontext(iff);
  222.     return(error);
  223. }
  224.  
  225. /* chkcnt
  226.  *
  227.  * simply counts the number of chunk pairs (type,id) in array
  228.  */
  229. LONG chkcnt(LONG *taggedarray)
  230. {
  231. LONG k = 0;
  232.  
  233.     while(taggedarray[k] != TAG_DONE) k++;
  234.     return(k>>1);
  235. }
  236.  
  237.  
  238. /* currentchunkis
  239.  *
  240.  * returns the ID of the current chunk (like ID_CAMG)
  241.  */
  242. LONG currentchunkis(struct IFFHandle *iff, LONG type, LONG id)
  243. {
  244. register struct ContextNode    *cn;
  245. LONG result = 0;
  246.  
  247.     if (cn = CurrentChunk (iff))
  248.         {
  249.         if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
  250.         }
  251.     return(result);
  252. }
  253.  
  254.  
  255. /* contextis
  256.  *
  257.  * returns the enclosing context of the current chunk (like ID_ILBM)
  258.  */
  259. LONG contextis(struct IFFHandle *iff, LONG type, LONG id)
  260. {
  261. register struct ContextNode    *cn;
  262. LONG result = 0;
  263.  
  264.        if (cn = (CurrentChunk (iff)))
  265.            {
  266.            if (cn = (ParentChunk(cn)))
  267.                {
  268.                if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
  269.                }
  270.        }
  271.  
  272.     D(bug("This is a %.4s %.4s\n",&cn->cn_Type,&cn->cn_ID));
  273.  
  274.     return(result);
  275. }
  276.  
  277.  
  278. /* getcontext()
  279.  *
  280.  * Continues to gather the context which was specified to parseifile(),
  281.  *  stopping at specified stop chunk, or end of context, or EOF
  282.  *
  283.  * Returns 0 (stopped on a stop chunk)
  284.  *      or IFFERR_EOC (end of context, not an error)
  285.  *      or IFFER_EOF (end of file)
  286.  */
  287. LONG getcontext(iff)
  288. struct    IFFHandle *iff;
  289. {
  290.     LONG error = 0L;
  291.  
  292.     /* Based on our parse initialization,
  293.      * ParseIFF() will return on a stop chunk (error = 0)
  294.      * or end of context for an ILBM FORM (error = IFFERR_EOC)
  295.      * or end of file (error = IFFERR_EOF)
  296.      */
  297.     return(error = ParseIFF(iff, IFFPARSE_SCAN));
  298. }
  299.  
  300.  
  301. /* nextcontext
  302.  *
  303.  * If you have finished parsing and reading your context (IFFERR_EOC),
  304.  *   nextcontext will enter the next context contained in the file
  305.  *   and parse it.
  306.  *
  307.  * Returns 0 or an IFFERR such as IFFERR_EOF (end of file)
  308.  */
  309.  
  310. LONG nextcontext(iff)
  311. struct    IFFHandle *iff;
  312. {
  313.     LONG error = 0L;
  314.  
  315.     error = ParseIFF(iff, IFFPARSE_STEP);
  316.  
  317.     D(bug("nextcontext: Got through next step\n"));
  318.  
  319.     return(error);
  320. }
  321.  
  322.  
  323. /* findpropdata
  324.  *
  325.  * finds specified chunk parsed from IFF file, and
  326.  *   returns pointer to its sp_Data (or 0 for not found)
  327.  */
  328. UBYTE *findpropdata(iff, type, id)
  329. struct IFFHandle    *iff;
  330. LONG type, id;
  331.     {
  332.     register struct StoredProperty    *sp;
  333.  
  334.     if(sp = FindProp (iff, type, id)) return(sp->sp_Data);
  335.     return(0);
  336.     }
  337.  
  338.  
  339. /*
  340.  * File I/O hook functions which the IFF library will call.
  341.  * A return of 0 indicates success (no error).
  342.  *
  343.  * Iffparse.library calls this code via struct Hook and Hook.asm
  344.  */
  345. static LONG
  346. __asm stdio_stream(register __a0 struct Hook *hook,
  347.          register __a2 struct IFFHandle *iff,
  348.          register __a1 struct IFFStreamCmd *actionpkt)    // MJP
  349. {
  350.     register FILE    *stream;
  351.     register LONG    nbytes;
  352.     register int    actual;
  353.     register UBYTE    *buf;
  354.     long    len;
  355.  
  356.     stream    = (FILE *) iff->iff_Stream;
  357.     if(!stream)    return(1);
  358.  
  359.     nbytes    = actionpkt->sc_NBytes;
  360.     buf    = (UBYTE *) actionpkt->sc_Buf;
  361.  
  362.     switch (actionpkt->sc_Command) {
  363.     case IFFCMD_READ:
  364.         do {
  365.             actual = nbytes > 32767 ? 32767 : nbytes;
  366.             if ((len=fread (buf, 1, actual, stream)) != actual)
  367.                 break;
  368.             nbytes -= actual;
  369.             buf += actual;
  370.         } while (nbytes > 0);
  371.         return (nbytes ? IFFERR_READ : 0 );
  372.  
  373.     case IFFCMD_WRITE:
  374.         do {
  375.             actual = nbytes > 32767 ? 32767 : nbytes;
  376.             if ((len=fwrite (buf, 1, actual, stream)) != actual)
  377.                 break;
  378.             nbytes -= actual;
  379.             buf += actual;
  380.         } while (nbytes > 0);
  381.         return (nbytes ? IFFERR_WRITE : 0);
  382.  
  383.     case IFFCMD_SEEK:
  384.         return ((fseek (stream, nbytes, 1) == -1) ? IFFERR_SEEK : 0);
  385.  
  386.     default:
  387.         /*  No _INIT or _CLEANUP required.  */
  388.         return (0);
  389.     }
  390. }
  391.  
  392. /* initiffasstdio (ie. init iff as stdio)
  393.  *
  394.  * sets up hook callback for the file stream handler above
  395.  */
  396. void initiffasstdio (iff)
  397. struct IFFHandle *iff;
  398. {
  399. //    extern LONG        HookEntry();    MJP
  400.     static struct Hook    stdiohook = {
  401.         { NULL },
  402. /*        (ULONG (*)()) HookEntry,        MJP
  403.         (ULONG (*)()) stdio_stream,
  404. */
  405.         (ULONG (*)()) stdio_stream,
  406.         (ULONG (*)()) NULL,
  407.         NULL
  408.     };
  409.  
  410.     /*
  411.      * Initialize the IFF structure to point to the buffered I/O
  412.      * routines.  Unbuffered I/O is terribly slow.
  413.      */
  414.     InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &stdiohook);
  415. }
  416.  
  417.  
  418. /*
  419.  * PutCk
  420.  *
  421.  * Writes one chunk of data to an iffhandle
  422.  *
  423.  */
  424. long PutCk(struct IFFHandle *iff, long id, long size, void *data)
  425.     {
  426.     long error = 0, wlen;
  427.  
  428.     D(bug("PutCk: asked to push chunk \"%.4s\" ($%lx) length %ld\n",&id,id,size));
  429.  
  430.     if(error=PushChunk(iff, 0, id, size))
  431.     {
  432.     D(bug("PutCk: PushChunk of %.4s, error = %s, size = %ld\n",
  433.         id, IFFerr(error), id));
  434.     }
  435.     else
  436.     {
  437.     D(bug("PutCk: PushChunk of %.4s, error = %ld\n",&id, error));
  438.  
  439.     /* Write the actual data */
  440.     if((wlen = WriteChunkBytes(iff,data,size)) != size)
  441.         {
  442.         D(bug("WriteChunkBytes error: size = %ld, wrote %ld\n",size,wlen));
  443.         error = IFFERR_WRITE;
  444.         }
  445.     else error = PopChunk(iff);
  446.     D(bug("PutCk: After PopChunk - error = %ld\n",error));
  447.     }
  448.     return(error);
  449.     }
  450.  
  451.